package com.example.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.locks.StampedLock;

@Service
@Slf4j
public class StampedLockExampleService {

    private final StampedLock stampedLock = new StampedLock();  // 创建 StampedLock 对象
    private int sharedResource = 0;  // 共享资源变量

    /**
     * 乐观读操作
     * 乐观读允许在不加锁的情况下读取数据。读取时可能有其他线程正在修改数据，因此在读取后要验证数据的一致性。
     */
    public void optimisticRead() {
        long stamp = stampedLock.tryOptimisticRead();  // 尝试获取乐观读锁，返回一个戳（stamp）
        try {
            log.info("乐观读获取到的共享资源: {}", sharedResource);  // 读取共享资源
            // 验证乐观读期间是否有写操作发生
            if (!stampedLock.validate(stamp)) {
                // 如果验证失败（意味着可能有写操作发生），则获取悲观读锁
                stamp = stampedLock.readLock();
                try {
                    log.info("重新获取读锁后的共享资源: {}", sharedResource);  // 重新读取共享资源
                } finally {
                    stampedLock.unlockRead(stamp);  // 释放悲观读锁
                }
            }
        } finally {
            // 尝试解锁。注意，这里仅在乐观读没有被升级为悲观锁时有效。
            stampedLock.unlock(stamp);
        }
    }

    /**
     * 写操作
     * 写操作使用写锁来确保线程安全。写锁是独占锁，保证同时只有一个线程可以修改共享资源。
     */
    public void write(int newValue) {
        long stamp = stampedLock.writeLock();  // 获取写锁，阻止其他线程的读或写操作
        try {
            sharedResource = newValue;  // 写入共享资源
            log.info("写入共享资源: {}", sharedResource);
        } finally {
            stampedLock.unlockWrite(stamp);  // 释放写锁
        }
    }
}
